
package com.dotools.reflection;

import java.lang.reflect.Method;

import android.os.IBinder;
import android.os.RemoteException;

public final class ReflectServiceManager {
    static final Class<?> sClsServiceManager;
    static final Method sMethodGetService;
    static final Method sMethodAddService;
    static final Method sMethodAddServiceIsolate;
    static final Method sMethodCheckService;
    static final Method sMethodListService;

    static {
        final String clsName = "android.os.ServiceManager";
        sClsServiceManager = ReflectionUtils.loadClassNoThrow(ClassLoader.getSystemClassLoader(), clsName);
        sMethodGetService = ReflectionUtils.findMethodNoThrow(sClsServiceManager, "getService", new Class<?>[] {
            String.class
        });
        sMethodAddService = ReflectionUtils.findMethodNoThrow(sClsServiceManager, "addService", new Class<?>[] {
                String.class, IBinder.class
        });
        sMethodAddServiceIsolate = ReflectionUtils.findMethodNoThrow(sClsServiceManager, "addService", new Class<?>[] {
                String.class, IBinder.class, boolean.class
        });
        sMethodCheckService = ReflectionUtils.findMethodNoThrow(sClsServiceManager, "checkService", new Class<?>[] {
            String.class
        });
        sMethodListService = ReflectionUtils.findMethodNoThrow(sClsServiceManager, "listServices", new Class<?>[] {});
    }

    /**
     * Returns a reference to a service with the given name.
     * 
     * @param name the name of the service to get
     * @return a reference to the service, or <code>null</code> if the service doesn't exist
     */
    public static IBinder getService(String name) {
        if (sMethodGetService != null) {
            try {
                return (IBinder) sMethodGetService.invoke(null, name);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * Place a new @a service called @a name into the service
     * manager.
     * 
     * @param name the name of the new service
     * @param service the service object
     */
    public static void addService(String name, IBinder service) {
        if (sMethodAddService != null) {
            try {
                sMethodAddService.invoke(null, name, service);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return;
    }

    /**
     * Place a new @a service called @a name into the service
     * manager.
     * 
     * @param name the name of the new service
     * @param service the service object
     * @param allowIsolated set to true to allow isolated sandboxed processes
     *            to access this service
     */
    public static void addService(String name, IBinder service, boolean allowIsolated) {
        if (sMethodAddServiceIsolate != null) {
            try {
                sMethodAddServiceIsolate.invoke(null, name, service, allowIsolated);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return;
    }

    /**
     * Retrieve an existing service called @a name from the
     * service manager. Non-blocking.
     */
    public static IBinder checkService(String name) {
        if (sMethodCheckService != null) {
            try {
                return (IBinder) sMethodCheckService.invoke(null, name);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * Return a list of all currently running services.
     */
    public static String[] listServices() {
        if (sMethodListService != null) {
            try {
                return (String[]) sMethodListService.invoke(null, (Object[]) null);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
